package com.xywei.config.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.AntPathMatcher;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	private SecurityCustomAuthenticationFailureHandler securityCustomAuthenticationFailureHandler;

	@Autowired
	private SecurityCustomUserDetailsService securityCustomUserDetailsService;

//	@Autowired
//	private SecurityCustomFilterInterceptor securityCustomFilterInterceptor;
	
	@Autowired
	private FilterInvocationSecurityMetadataSource securityMetadataSource;
	
	@Autowired
	private  AccessDecisionManager accessDecisionManager;

	@Bean(name = "passwordEncoder")
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean(name = "securityMetadataSource", initMethod = "initResourceConfigAuthority")
	public FilterInvocationSecurityMetadataSource securityCustomMetadataSource() {
		FilterInvocationSecurityMetadataSource securityCustomMetadataSource = new SecurityCustomMetadataSource();
		return securityCustomMetadataSource;
	}

	@Bean(name = "accessDecisionManager")
	public AccessDecisionManager accessDecisionManager() {
		AccessDecisionManager accessDecisionManager = new SecurityCustomAccessDecisionManager();
		return accessDecisionManager;
	}
	
	@Bean(name = "securityCustomFilterInterceptor")
	public SecurityCustomFilterInterceptor securityCustomFilterInterceptor() {
		SecurityCustomFilterInterceptor securityCustomFilterInterceptor = new SecurityCustomFilterInterceptor();
		securityCustomFilterInterceptor.setAccessDecisionManager(accessDecisionManager);
		securityCustomFilterInterceptor.setSecurityMetadataSource(securityMetadataSource);
		return securityCustomFilterInterceptor;
	}

	/**
	 * 不需要拦截的静态资源
	 */
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/css/**", "/js/**", "/images/**");
	}

	/**
	 * 配置基本权限
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
//		http.csrf().disable()// 必须禁用，否则无法提交表单登陆
		http//开启CSRF
				.authorizeRequests().anyRequest().authenticated()//
				.and()//
				.formLogin().loginPage("/userLoginPage").loginProcessingUrl("/userLoginProcessing").permitAll()// 登陆的相关接口都放行
//				.failureForwardUrl("/userLoginPage")//和failureHandler二选一
				.failureHandler(securityCustomAuthenticationFailureHandler)//
				.and()//
				.logout()
				.logoutUrl("/logout").logoutSuccessUrl("/userLoginPage")//
				.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))//关闭只能POST请求的方式进行logout，必须在最后的logout配置
				.and()//
				.addFilterBefore(securityCustomFilterInterceptor(), FilterSecurityInterceptor.class);
	}

	/**
	 * 自定义数据
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(securityCustomUserDetailsService).passwordEncoder(passwordEncoder());
	}

}
